﻿using EWSEditor.Common.Extensions;
using EWSEditor.Exchange;
using EWSEditor.Forms;
using Microsoft.Exchange.WebServices.Data;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EWSEditor.CRM.Forms
{
    public partial class CrmServiceDialog : DialogForm
    {

        private ExchangeService _service;

        public CrmServiceDialog(bool HideBase, BrowserForm browserForm)
        {

            if (!HideBase)
            {
                InitializeComponent();
            }

            CrmOrgMailboxCache.SupportMode = false;
        }

        public CrmServiceDialog(ExchangeService service)
        {
            InitializeComponent();
            _service = service;
            CrmOrgMailboxCache.SupportMode = false;
        }

        private void btnSignIn_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor = System.Windows.Forms.Cursors.WaitCursor;
                ValidateInputs();
                EnsureAddressMatch();
                CrmAuthInfoFactory.SetProperties(txtbxUsername.Text, txtbxPassword.Text, txtbxOrgUrl.Text, txtTarget.Text, chkHomeRealm.Checked, txtbxHomeRealm.Text);
                lblProgress.Text = "Authenticating...";
                prgLoad.Value = 20;
                OrganizationServiceProxy orgProxy = CrmAuthInfoFactory.GetOrgProxy();
                prgLoad.Value = 50;

                lblProgress.Text = "Validating Mailbox...";
                Application.DoEvents();
                Entity mailbox = ValidateAndSetTargetMailbox(orgProxy, txtTarget.Text); 
                DetermineUserOrQueueMailbox(mailbox, orgProxy);
                prgLoad.Value = 80;

                lblProgress.Text = "Retrieving Configuration...";
                Application.DoEvents();
                SetOrgMailboxCache(mailbox, orgProxy);
                prgLoad.Value = 100;
                DialogResult = DialogResult.OK;
            }

            catch (Exception ex)
            {
                CrmAuthInfoFactory.ClearAuthProperties();
                prgLoad.Value = 0;
                lblProgress.Text = "";
                Application.DoEvents();
                if (ex.InnerException != null)
                {
                    if (ex.InnerException.Message == "Authentication Failure")
                    {
                        MessageBox.Show("Dynamics 365 Authentication Failed. Please check your credentials.");
                        return;
                    }
                }
                if (!string.IsNullOrEmpty(ex.Message) && ex.Message == "Access is denied.")
                {
                    MessageBox.Show("Dynamics 365 Authentication Failed. Please check your credentials.");
                    return;
                }
                CrmClientException.ShowException(ex);
                return;
            }

            finally
            {
                Cursor = System.Windows.Forms.Cursors.Default;
            }

        }

        protected virtual void SetOrgMailboxCache(Entity mailbox, OrganizationServiceProxy orgProxy)
        {
            CrmOrgMailboxCache.TargetMailboxEmailAddress = (string)mailbox["emailaddress"];
            CrmOrgMailboxCache.SetLoggedInUser(orgProxy);
            CrmOrgMailboxCache.RetrieveOrganization(orgProxy);
            CrmOrgMailboxCache.DoesUserOwnMailbox(mailbox);
            CrmOrgMailboxCache.RetrieveUserOrQueueSettings(orgProxy);
        }

        protected virtual void DetermineUserOrQueueMailbox(Entity mailbox, OrganizationServiceProxy orgProxy)
        {
            Guid regardingid = ((EntityReference)mailbox["regardingobjectid"]).Id;
            QueryByAttribute query = new QueryByAttribute("systemuser");
            query.ColumnSet = new ColumnSet();
            query.Attributes.AddRange("systemuserid");
            query.Values.AddRange(regardingid);
            EntityCollection queues = orgProxy.RetrieveMultiple(query);

            if (queues.Entities.Count == 0)
            {
                CrmOrgMailboxCache.TargetMailboxIsQueue = true;
                return;
            }

            CrmOrgMailboxCache.TargetMailboxIsQueue = false;
        }

        protected virtual Entity ValidateAndSetTargetMailbox(OrganizationServiceProxy orgProxy, string emailAddress)
        {

            QueryByAttribute query = new QueryByAttribute("mailbox");
            query.ColumnSet = new ColumnSet() { AllColumns = true };
            query.Attributes.AddRange("emailaddress");
            query.Values.AddRange(emailAddress);
            query.Attributes.AddRange("statecode");
            query.Values.AddRange(0);
            EntityCollection mailboxes = orgProxy.RetrieveMultiple(query);

            if (mailboxes.Entities.Count < 1)
            {
                throw new Exception("Did not find an active Dynamics 365 mailbox with the supplied email address.");
            }

            if (mailboxes.Entities.Count > 1)
            {
                throw new Exception("Found more than one active Dynamics 365 mailbox with the supplied email address.");
            }
            CrmAuthInfoFactory._targetValidated = true;
            CrmOrgMailboxCache.TargetMailbox = mailboxes[0];
            return CrmOrgMailboxCache.TargetMailbox;
        }

        protected virtual void ValidateInputs()
        {
            //Validate Inputs
            if (txtbxOrgUrl.Text == "https://<org>.crm.dynamics.com/XrmServices/2011/Organization.svc")
            {
               throw new Exception("Please supply a valid Dynamics 365 Organization Service URL.");
            }
            if (string.IsNullOrEmpty(txtbxUsername.Text))
            {
                throw new Exception("Please supply a valid Dynamics 365 Username.");
            }
            if (string.IsNullOrEmpty(txtbxPassword.Text))
            {
                throw new Exception("Please supply a valid Dynamics 365 Password.");
            }
            if (string.IsNullOrEmpty(txtTarget.Text) || !txtTarget.Text.Contains("@"))
            {
                throw new Exception("Please supply a target Dynamics 365 mailbox with a valid e-mail address. The email address should match the email address of the account being accessed in the Exchange Service and be linked to a valid Dynamics 365 Mailbox.");
            }
        }

        protected virtual void EnsureAddressMatch()
        {

            if (_service.ImpersonatedUserId != null)
            {
                if (string.Compare(_service.ImpersonatedUserId.Id, txtTarget.Text, true) != 0)
                {
                    throw new Exception("The impersonated Exchange Account does not match the Dynamics 365 Target Mailbox.");
                }
            }
            else
            {
                string accountname = _service.GetServiceAccountName();
                if (accountname.Contains("@"))
                {
                    if (string.Compare(accountname, txtTarget.Text, true) != 0)
                    {
                        throw new Exception("The connected Exchange Account does not match the Dynamics 365 Target Mailbox.");
                    }
                }
            }

        }

        public static DialogResult ShowDialog(bool custom, ExchangeService service)
        {
            CrmServiceDialog dialog = new CrmServiceDialog(service);
            DialogResult res = dialog.ShowDialog();
            return res;
        }

        private void CrmServiceDialog_Load(object sender, EventArgs e)
        {
            if (_service == null)
            {
                return;
            }

            if (_service.ImpersonatedUserId != null)
            {
                txtTarget.Text = _service.ImpersonatedUserId.Id;
            }
            else
            {
                string account = _service.GetServiceAccountName();
                if (account.Contains("@"))
                {
                    txtTarget.Text = account;
                }
            }
        }

        private void lblProgress_Click(object sender, EventArgs e)
        {

        }

        private void chkHomeRealm_CheckedChanged(object sender, EventArgs e)
        {
            if (chkHomeRealm.Checked)
            {
                txtbxHomeRealm.Enabled = true;
                return;
            }
            txtbxHomeRealm.Enabled = false;

        }

        private void lblSignInLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            MessageBox.Show("Sign in using your Dynamics 365 account information. The account you specify will need the necessary permissions to:\n\n1. Retrieve the Dynamics 365 Target Mailbox\n2. Retrieve the User or Queue Settings associated with the Dynamics 365 Target Mailbox\n3. Retrieve the Email Server Profile associated with the Dynamics 365 Target Mailbox\n4. Retrieve the Organization settings\n\nThe Dynamics 365 Target Mailbox must match the connected EWS Editor mailbox.\n\nThe Organization Url should be specified in the following format:\n\nhttps://orgname.server.com", "Sign In Instructions");
        }
    }
}
